package top.codef.secure.config;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.ConditionalOnDefaultWebSecurity;
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.util.ClassUtils;

import top.codef.secure.config.interfaces.CerberusHttpSecuriryCustormer;
import top.codef.secure.config.interfaces.CerberusHttpSecurityConfig;

@Configuration
@AutoConfiguration(before = ManagementWebSecurityAutoConfiguration.class, after = {
		HealthEndpointAutoConfiguration.class, InfoEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
		OAuth2ClientAutoConfiguration.class, OAuth2ResourceServerAutoConfiguration.class,
		Saml2RelyingPartyAutoConfiguration.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnDefaultWebSecurity
public class DefaultSecurityConfiguration {

	@Autowired
	private List<CerberusHttpSecurityConfig> cerberusSecurityConfigs;

	@Autowired(required = false)
	private CerberusHttpSecuriryCustormer cerberusHttpSecuriryCustormer;

	private final Log logger = LogFactory.getLog(DefaultSecurityConfiguration.class);

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		logger.debug("Cerberus 安全配置");
		http.authorizeHttpRequests((requests) -> {
			requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll();
		});
		if (ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", null)) {
			http.cors(x -> {
			});
		}
		http.requestCache(x -> x.disable()).headers(x -> x.disable());
		for (CerberusHttpSecurityConfig cerberusSecurityConfig : cerberusSecurityConfigs)
			cerberusSecurityConfig.secure(http);
		if (cerberusHttpSecuriryCustormer != null) {
			cerberusHttpSecuriryCustormer.custom(http);
		}
		return http.build();
	}

	@Bean
	@ConditionalOnMissingBean
	PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder(10);
	}
}
